/*
 * Copyright (c) 2017. danlu.com Co.Ltd. All rights reserved.
 */

package cn.com.dhc.danlu.dlware.net.func;

import com.danlu.lib.net.constant.ErrorCode;
import com.danlu.lib.net.exception.ObviousException;

import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.functions.Func1;
import rx.functions.Func2;

/**
 * User: Geek_Soledad(wuhaiyang@andthink.cn)
 * Date: 2016-09-19
 * Time: 00:15
 * Description useage:.compose(OperatorUtils.<GetCouponWithMerchResponse>defaultSchedulers())
 * .retryWhen(new RetryWhenNetworkException())
 */
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
    private int count = 3;//retry count
    private long delay = 3000;//delay time

    public RetryWhenNetworkException() {

    }

    public RetryWhenNetworkException(int count) {
        this.count = count;
    }

    public RetryWhenNetworkException(int count, long delay) {
        this.count = count;
        this.delay = delay;
    }

    private static class Wrapper {
        private int index;
        private Throwable throwable;

        public Wrapper(Throwable throwable, int index) {
            this.index = index;
            this.throwable = throwable;
        }
    }

    @Override
    public Observable<?> call(Observable<? extends Throwable> observable) {
        return observable
                .zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() {
                    @Override
                    public Wrapper call(Throwable throwable, Integer integer) {
                        return new Wrapper(throwable, integer);
                    }
                }).flatMap(new Func1<Wrapper, Observable<?>>() {
                    @Override
                    public Observable<?> call(Wrapper wrapper) {
                        if (isHttpException(wrapper.throwable) && wrapper.index < count + 1) {
                            return Observable.timer(delay + (wrapper.index - 1) * delay, TimeUnit.MILLISECONDS);
                        }
                        return Observable.error(wrapper.throwable);
                    }
                });
    }

    private boolean isHttpException(Throwable throwable) {
        if (throwable instanceof ObviousException) {
            ObviousException oe = (ObviousException) throwable;
            int code = oe.getCode();
            if (code == ErrorCode.HTTP_ERROR || code == ErrorCode.NETWORD_ERROR) {
                return true;
            }
        }
        return false;
    }

}
